package com.birdpiss.commons.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.List;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
import org.springframework.jdbc.core.simple.ParameterizedRowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import com.birdpiss.commons.dao.interfaces.TransactionDao;
import com.birdpiss.commons.domain.Transaction;
import com.birdpiss.commons.domain.TransactionStatus;

/**
 * The Class DefaultTransactionDao.
 *
 * @author mark
 */
@Repository("transactionDao")
public class DefaultTransactionDao extends SimpleJdbcTemplate implements TransactionDao {

	private static final Logger log = Logger.getLogger(TransactionDao.class);
	protected static final String [] COLUMNS = { "Id", "DebitAccountId", "CreditAccountId", "Amount", "StatusId" };
	protected TransactionRowMapper transactionRowMapper = new TransactionRowMapper();
	private PreparedStatementCreatorFactory insertTransaction;

	protected static final String SELECT_BY_ID =
		"SELECT " + StringUtils.arrayToCommaDelimitedString(COLUMNS) +
		" FROM transaction " +
		"WHERE Id = ?";

	protected static final String INSERT_TRANSACTION =
		"INSERT INTO transaction " +
		"(" + COLUMNS[1] + ", " + COLUMNS[2] + ", " + COLUMNS[3] + ", " + COLUMNS[4] + ") " +
		"VALUES (?, ?, ?, ?)";

	/**
	 * Instantiates a new default transaction dao.
	 *
	 * @param dataSource the data source
	 */
	@Autowired
	public DefaultTransactionDao(@Qualifier("birdpiss") DataSource dataSource) {
		super(dataSource);
		this.initializePreparedStatements();
	}

	/**
	 * Initialize prepared statements.
	 */
	private void initializePreparedStatements() {
		this.insertTransaction =
			new PreparedStatementCreatorFactory(INSERT_TRANSACTION,
					                            new int[] { Types.INTEGER, Types.INTEGER, Types.DECIMAL, Types.INTEGER });

		this.insertTransaction.setReturnGeneratedKeys(true);
	}

	/* (non-Javadoc)
	 * @see com.birdpiss.commons.dao.interfaces.TransactionDao#getTransactionById(java.lang.Integer)
	 */
	@Override
	public Transaction getTransactionById(Integer accountId) {
		if (log.isDebugEnabled()) log.debug("Getting transaction id: " + accountId);
		List<Transaction> transaction = this.query(SELECT_BY_ID, this.transactionRowMapper, accountId);
		return ((transaction != null) && (transaction.size() == 1)) ? transaction.get(0) : null;
	}

	/* (non-Javadoc)
	 * @see com.birdpiss.commons.dao.interfaces.TransactionDao#insertTransaction(com.birdpiss.commons.domain.Transaction)
	 */
	@Override
	public Transaction insertTransaction(Transaction transaction) {
		if (log.isDebugEnabled()) log.debug("Inserting Transaction: " + transaction);

		KeyHolder keyHolder = new GeneratedKeyHolder();
		this.getJdbcOperations().update(
				this.insertTransaction.newPreparedStatementCreator(new Object[] {
						transaction.getDebitAccountId(),
						transaction.getCreditAccountId(),
						transaction.getAmount(),
						transaction.getTransactionStatus().value() }),
					keyHolder);

		int primaryKey = keyHolder.getKey().intValue();
		if (log.isDebugEnabled()) log.debug("Inserted Transaction id: " + primaryKey);
		transaction.setId(primaryKey);

		return transaction;
	}

	/**
	 * The class TransactionRowMapper.
	 */
	protected class TransactionRowMapper implements ParameterizedRowMapper<Transaction> {

		/* (non-Javadoc)
		 * @see org.springframework.jdbc.core.simple.ParameterizedRowMapper#mapRow(java.sql.ResultSet, int)
		 */
		@Override
		public Transaction mapRow(ResultSet rs, int rowNum) throws SQLException {

			Transaction transaction = new Transaction();

			transaction.setId(rs.getInt(COLUMNS[0]));
			transaction.setDebitAccountId(rs.getInt(COLUMNS[1]));
			transaction.setCreditAccountId(rs.getInt(COLUMNS[2]));
			transaction.setAmount(rs.getBigDecimal(COLUMNS[3]));
			transaction.setTransactionStatus(TransactionStatus.getTransactionStatus(rs.getInt(COLUMNS[4])));

			return transaction;
		}

	}

}
